package com.work.demo.enumdemo;

import cn.hutool.bloomfilter.BitMapBloomFilter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description: 布隆过滤器
 * @author: LinYa
 * @date: 2021/6/29
 */
public class BloomFilter implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 * 二进制向量的位数，相当于能存储1000万条左右，误报率为千万分之一
	 */
//    private static final int BIT_SIZE = 2 << 13 ;
	/**
	 * 用于生成信息指纹的8个随机数，最好选取质数
	 */
	private static final int[] SEEDS = new int[]{3, 5, 7, 11, 13, 31, 37, 61};


	private BitSet bits;

	/**
	 * 用于存储8个随机哈希值对象
	 */
	private Hash[] func;

	public BloomFilter(int bitSize) {
		bits = new BitSet(2 << bitSize);
		func = new Hash[SEEDS.length];
		for (int i = 0; i < SEEDS.length; i++) {
			func[i] = new Hash(2 << bitSize, SEEDS[i]);
		}
	}

	/**
	 * 使用自定的多个过滤器建立BloomFilter
	 */
	public BloomFilter(int bitSize, int seedsLength, Hash[] func, BitSet bits) {
		this(bitSize);
		this.func = func;
		this.bits = bits;
	}

	/**
	 * 像过滤器中添加字符串
	 */
	public void addValue(String value) {
		//将字符串value哈希为8个或多个整数，然后在这些整数的bit上变为1
		if (value != null) {
			for (Hash f : func) {
				bits.set(f.hash(value), true);
			}
		}

	}

	/**
	 * 判断字符串是否包含在布隆过滤器中
	 */
	public boolean contains(String value) {
		if (value == null) {
			return false;
		}

		boolean ret = true;

		//将要比较的字符串重新以上述方法计算hash值，再与布隆过滤器比对
		for (Hash f : func) {
			ret = ret && bits.get(f.hash(value));
		}
		return ret;
	}

	/**
	 * 随机哈希值对象
	 */

	public static class Hash implements Serializable {
		private static final long serialVersionUID = 86561282227145471L;

		private int size;//二进制向量数组大小
		private int seed;//随机数种子

		Hash(int cap, int seed) {
			this.size = cap;
			this.seed = seed;
		}

		/**
		 * 计算哈希值(也可以选用别的恰当的哈希函数)
		 */
		int hash(String value) {
			int result = 0;
			int len = value.length();
			for (int i = 0; i < len; i++) {
				result = seed * result + value.charAt(i);
			}

			return (size - 1) & result;
		}
	}


	public static void main(String[] args) {
		List<String> phoneList = new ArrayList<>();
		List<String> list = new ArrayList<>();
		List<String> smallList = new ArrayList<>();
		for (int i = 0; i < 10000000; i++) {
			String s = "12436sdfsdas" + i;
			String s1 = "12436sdfsd" + i;
			phoneList.add(s);
			list.add(s1);
			if (i < 1000) {
				smallList.add(s);
			}
		}
		BloomFilter bloomFilter = new BloomFilter(16);
//		BitMapBloomFilter bloomFilter = new BitMapBloomFilter(10);
//		smallList.forEach(bloomFilter::add);

//		List<BloomFilter> bloomFilterList = new ArrayList<>(3);
//		for (int i = 0; i < 3; i++) {
//			//生成新布隆过滤器 bit的长度和指纹，配置在配置文件里
//			BloomFilter bloomFilter = new BloomFilter(17);
//			//添加到布隆过滤器里
//			smallList.forEach(bloomFilter::addValue);
//			bloomFilterList.add(bloomFilter);
//		}
		smallList.forEach(bloomFilter::addValue);
		List<String> stringList = sddsasd(phoneList, list, bloomFilter);
//		List<String> stringList = sddsasd(phoneList, phoneList, bloomFilter);
		System.out.println(stringList.size());
	}


	public static List<String> gridPostBloomData(List<String> allDataList, List<String> incrDataList, List<BloomFilter> filter) {
		long begin = System.currentTimeMillis();
		List<String> smallList = new ArrayList<>();

		getSmallList(allDataList, filter, smallList);

		getSmallList(incrDataList, filter, smallList);

//		if (CollectionUtil.isNotEmpty(allDataList)){
//			smallList.addAll(allDataList);
//		}
//		if (CollectionUtil.isNotEmpty(incrDataList)){
//			smallList.addAll(incrDataList);
//		}
		long end = System.currentTimeMillis();
		System.out.println("数据求交结束时间 --> gridBloomData() -->  {}" + end);
		long l = end - begin;
		System.out.println("JAVA预求交总耗时 --> gridBloomData()  -->  {}:" + l);
//		log.info("JAVA预求交总耗时 --> gridBloomData()  -->  {}:", l);
		System.out.println("JAVA预求交结果总长度  --> gridBloomData() --> 长度是 {}" + smallList.size());
//		log.info("JAVA预求交结果总长度  --> gridBloomData() --> 长度是 {}", filterPhoneList.size());
		return smallList;
	}

	private static void getSmallList(List<String> allDataList, List<BloomFilter> filter, List<String> smallList) {
		allDataList.forEach(s -> {
			AtomicInteger i = new AtomicInteger();
			filter.forEach(f -> {
				if (f.contains(s)) {
					i.incrementAndGet();
				}
				if (i.get() == 3) {
					smallList.add(s);
				}
			});
		});
	}


	private static List<String> sddsasd(List<String> allDataList, List<String> incrDataList, BitMapBloomFilter filter) {
		List<String> filterPhoneList = new ArrayList<>();
		//求交
		allDataList.forEach(s1 -> {
			if (filter.contains(s1)) {
				filterPhoneList.add(s1);
			}
		});
		incrDataList.forEach(s1 -> {
			if (filter.contains(s1)) {
				filterPhoneList.add(s1);
			}
		});
		return filterPhoneList;
	}

	private static List<String> sddsasd(List<String> allDataList, List<String> incrDataList, BloomFilter filter) {
		List<String> filterPhoneList = new ArrayList<>();
		//求交
		allDataList.forEach(s1 -> {
			if (filter.contains(s1)) {
				filterPhoneList.add(s1);
			}
		});
		incrDataList.forEach(s1 -> {
			if (filter.contains(s1)) {
				filterPhoneList.add(s1);
			}
		});
		return filterPhoneList;
	}

}

